/**
 *  Copyright (c) 2024 Ebaina
 *  hieuler u-boot is licensed under Mulan PSL v2.
 *  You can use this software according to the terms and conditions of the Mulan PSL v2. 
 *  You may obtain a copy of Mulan PSL v2 at:
 *           http://license.coscl.org.cn/MulanPSL2 
 *  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER 
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR 
 *  FIT FOR A PARTICULAR PURPOSE.  
 *  See the Mulan PSL v2 for more details.  
 */

#include <common.h>
#include <command.h>
#include <string.h>
#include <env.h>
#include "hex.h"

#define CMD_HEX_HELP "<-o|-d|-h> <name> <value>"

#define BUFFER_SIZE 40

unsigned long atoi(char* value,int odh)
{
    unsigned long data = 0;
    int i;

    const int times[4] = {
        [FLAG_OCT] = 8,
        [FLAG_DEC] = 10,
        [FLAG_HEX] = 16,
    };

    for(i=0;value[i];i++){
        data *= times[odh];

        if(value[i]>='0'&&value[i]<='7') 
            { data += value[i] - '0'; continue; }
        
        if((odh==FLAG_DEC||odh==FLAG_HEX)&&value[i]>='8'&&value[i]<='9') 
            { data += value[i] - '0'; continue; }
        
        if((odh==FLAG_HEX)&&value[i]>='a'&&value[i]<='f') 
            { data += value[i] - 'a' + 10; continue; }
        
        if((odh==FLAG_HEX)&&value[i]>='A'&&value[i]<='F') 
            { data += value[i] - 'A' + 10; continue; }

        break;
    }

    if(value[i])
        data /= times[odh];
    
    return data;
}

unsigned long atoi_auto(char* value)
{
    unsigned long data = 0;

    if(value==NULL)
        return 0;

    if(value[0]=='0'){
        if(value[1]=='x')
            data = atoi(value+2,FLAG_HEX);
        else
            data = atoi(value+1,FLAG_OCT);
    }
    else if(value[0]>='0'&&value[0]<='9'){
        data = atoi(value,FLAG_DEC);
    }

    return data;
}

int do_hex(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    char buffer[BUFFER_SIZE];
    int odh = 0;
    char* name = NULL;
    char* value = NULL;
    unsigned long data;
    
    for(int i=1;i<argc;i++){
        if(argv[i][0]=='-'){
            switch (argv[i][1])
            {
            case 'o':odh = FLAG_OCT;break;
            case 'd':odh = FLAG_DEC;break;
            case 'h':odh = FLAG_HEX;break;

            default:
                goto argv_err;
            }
            continue;
        }
        if(!name) { name = argv[i]; continue; }
        if(!value) { value = argv[i]; continue; }
    }
    if(name==NULL||value==NULL||odh==0)
        goto argv_err;

    if(value[0]=='0'){
        if(value[1]=='x')
            data = atoi(value+2,FLAG_HEX);
        else
            data = atoi(value+1,FLAG_OCT);
    }
    else if(value[0]>='0'&&value[0]<='9'){
        data = atoi(value,FLAG_DEC);
    }
    else {
        goto argv_err;
    }

    switch (odh)
    {
    case FLAG_OCT:snprintf(buffer,BUFFER_SIZE,"%lo",data);break;
    case FLAG_DEC:snprintf(buffer,BUFFER_SIZE,"%ld",data);break;
    case FLAG_HEX:snprintf(buffer,BUFFER_SIZE,"%lx",data);break;
    
    default:
        goto argv_err;
    }

    env_set(name,buffer);
    buffer[0]='G';
    return 0;

argv_err:
    printf("args error!\n%s\n",CMD_HEX_HELP);
    return 1;
}

U_BOOT_CMD(
	hex, 4, 1, do_hex,
	"convert between hexadecimal, decimal, and octal",
	CMD_HEX_HELP
);
